package com.nageoffer.jobtrain.projects.service.handler.question.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.nageoffer.jobtrain.projects.common.biz.user.UserContext;
import com.nageoffer.jobtrain.projects.dao.entity.OjQuestionDO;
import com.nageoffer.jobtrain.projects.dao.entity.OjQuestionESDO;
import com.nageoffer.jobtrain.projects.dao.mapper.OjQuestionMapper;
import com.nageoffer.jobtrain.projects.elasticsearch.OjQuestionRepository;
import com.nageoffer.jobtrain.projects.mq.event.OjQuestionSubmitEvent;
import com.nageoffer.jobtrain.projects.mq.producer.OjQuestionSubmitProducer;
import com.nageoffer.jobtrain.projects.service.handler.question.OjQuestionSubmitCodeByRocketMQTemplate;
import com.nageoffer.jobtrain.projects.service.handler.question.dto.OjQuestionJudgeCaseDTO;
import com.nageoffer.jobtrain.projects.service.handler.question.dto.OjQuestionSubmitCodeTemplateDTO;
import com.nageoffer.jobtrain.projects.service.handler.question.dto.OjQuestionSubmitJudgeDTO;
import com.nageoffer.jobtrain.projects.toolkit.StringSplicingUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 用户提交代码类型为Java判断逻辑 - 提交到mq中进行等待消费
 * author：唐晨
 * 问题：
 * 1、资源滥用/攻击 - 死循环问题等
 * 2、安全漏洞 - 存在病毒导致系统瘫痪
 * 3、数据泄露 - 访问文件等情况
 * 4、相互干扰 - 多个用户同时提交代码
 * 方案：放入 docker容器中执行
 */
@Component
@RequiredArgsConstructor
public class OjQuestionSubmitCodeTypeJavaByRocketMQTemplate implements OjQuestionSubmitCodeByRocketMQTemplate {
    private final OjQuestionSubmitProducer ojQuestionSubmitProducer;
    private final OjQuestionRepository ojQuestionRepository;
    private final OjQuestionMapper ojQuestionMapper;

    @Override
    public void submitCodeByRocketMQ(OjQuestionSubmitCodeTemplateDTO requestParam) {
        // 先从ES中获取OJ题目详情信息
        OjQuestionESDO ojQuestionESDO = ojQuestionRepository.findById(requestParam.getQuestionId()).orElse(null);
        OjQuestionSubmitJudgeDTO ojQuestionSubmitJudgeDTO;
        if (ojQuestionESDO != null) {
            ojQuestionSubmitJudgeDTO = OjQuestionSubmitJudgeDTO.builder()
                    .difficulty(ojQuestionESDO.getDifficulty())
                    .timeLimit(ojQuestionESDO.getTimeLimit())
                    .spaceLimit(ojQuestionESDO.getSpaceLimit())
                    .build();
        } else {
            // ES中未获取到数据，直接从数据库中提取
            OjQuestionDO ojQuestionDO = ojQuestionMapper.selectById(requestParam.getQuestionId());
            ojQuestionSubmitJudgeDTO = OjQuestionSubmitJudgeDTO.builder()
                    .difficulty(ojQuestionDO.getDifficulty())
                    .timeLimit(ojQuestionDO.getTimeLimit())
                    .spaceLimit(ojQuestionDO.getSpaceLimit())
                    .build();
            // 刷新数据到ES中
            ojQuestionESDO = new OjQuestionESDO();
            BeanUtil.copyProperties(ojQuestionDO, ojQuestionESDO);
            ojQuestionRepository.save(ojQuestionESDO);
        }
        ojQuestionSubmitJudgeDTO.setPhoneNumber(UserContext.getUsername());
        ojQuestionSubmitJudgeDTO.setQuestionId(requestParam.getQuestionId());
        ojQuestionSubmitJudgeDTO.setCodeType(requestParam.getCodeType());
        ojQuestionSubmitJudgeDTO.setContestId(requestParam.getContestId());
        ojQuestionSubmitJudgeDTO.setUserSubmitCode(requestParam.getUserSubmitCode());
        // 整体编译、运行代码需要将代码进行拼接
        ojQuestionSubmitJudgeDTO.setTotalCode(StringSplicingUtils.codeConnect(requestParam.getUserSubmitCode(), ojQuestionESDO.getMainFunction()));

        // 提取测试用例
        List<OjQuestionJudgeCaseDTO> ojQuestionJudgeCaseList = JSONUtil.toList(ojQuestionESDO.getQuestionCase(), OjQuestionJudgeCaseDTO.class);
        ojQuestionSubmitJudgeDTO.setInputList(ojQuestionJudgeCaseList.stream().map(OjQuestionJudgeCaseDTO::getInput).toList());
        ojQuestionSubmitJudgeDTO.setOutputList(ojQuestionJudgeCaseList.stream().map(OjQuestionJudgeCaseDTO::getOutput).toList());

        // 向MQ中发送提交代码消息事件
        ojQuestionSubmitProducer.sendMessage(BeanUtil.toBean(ojQuestionSubmitJudgeDTO, OjQuestionSubmitEvent.class));
    }
}
